package v1

import (
	"context"
	"time"
	"wxpay/internal/dto"
	"wxpay/internal/service"
	wxpay "wxpay/pkg/api/v1"
	"wxpay/pkg/merrors"
	"wxpay/pkg/util"
)

func convertSettleInfo(req *wxpay.JSAPIPreCreateRequest) (r *dto.SettleInfo) {
	if req.SettleInfo != nil {
		r = &dto.SettleInfo{
			ProfitSharing: req.SettleInfo.ProfitSharing,
			SubsidyAmount: int(req.SettleInfo.SubsidyAmount),
		}
	}
	return
}

func convertTradeDto(req *wxpay.JSAPIPreCreateRequest) (r *dto.TradeDTO, err error) {
	const op merrors.Op = "convertTradeDto"
	// 最长有效时间 2H
	const MaxExpireTime = 2 * time.Hour
	now := util.GetNow()
	var exp time.Time
	if req.TimeExpire != "" {
		exp, err = util.ParseTime(util.LayoutSecondWithTimeZoneAndT, req.TimeExpire)
		if err != nil {
			return nil, err
		}
		if now.Add(MaxExpireTime).Before(exp) {
			return nil, merrors.E(op, merrors.Invalid, merrors.ErrInvalidArguments, "交易过期时间不允许设置超过2小时")
		}
	} else {
		exp = util.GetNow().Add(MaxExpireTime)
	}
	r = &dto.TradeDTO{
		BrandID:    req.BrandId,
		MchID:      req.MchId,
		SubMchID:   req.SubMchId,
		AppID:      req.AppId,
		SubAppID:   req.SubAppId,
		OutTradeNo: req.OutTradeNo,
		ExpireTime: exp,
		SettleInfo: convertSettleInfo(req),
		AmountInfo: dto.AmountInfo{
			Total:    uint(req.Amount.Total),
			Currency: req.Amount.Currency,
		},
		PayerInfo: &dto.PayerInfo{
			SpOpenID:  req.Payer.OpenId,
			SubOpenID: req.Payer.SubOpenId,
		},
		Description: req.Description,
		CreateTime:  util.GetNow(),
		UpdateTime:  util.GetNow(),
	}
	// 复写币种字段,默认为人民币
	if r.AmountInfo.Currency == "" {
		r.AmountInfo.Currency = "CNY"
	}
	return
}

// JSAPI预下单 post: /api/v1/wxpay/jsapi-precreate
func (s *Server) JSAPIPreCreate(ctx context.Context, req *wxpay.JSAPIPreCreateRequest) (*wxpay.JSAPIPreCreateResponse, error) {
	const op merrors.Op = "JSAPIPreCreate"
	tradeDto, err := convertTradeDto(req)
	if err != nil {
		return nil, merrors.E(op, merrors.InvalidArgument, merrors.ErrInvalidArguments, err)
	}
	// TODO 根据子商户签约的费率填充服务费率
	tradeDto.SetServiceRate(60)
	resp, err := service.NewTransService(s.d).JSAPIPrepay(ctx, *tradeDto)
	if err != nil {
		return nil, merrors.E(op, merrors.Invalid, err)
	}
	return &wxpay.JSAPIPreCreateResponse{
		AppId:      resp.AppID,
		TimeStamp:  resp.TimeStamp,
		Nonce:      resp.Nonce,
		Package:    resp.Package,
		SignType:   resp.SignType,
		PaySign:    resp.PaySign,
		ExpireTime: util.TimePtrToString(&resp.ExpireTime, util.LayoutSecondWithTimeZoneAndT),
	}, nil
}

// 查询trade GET /api/v1/wxpay/trades/{out_trade_no}
func (s *Server) TradeQuery(ctx context.Context, req *wxpay.TradeQueryRequest) (*wxpay.TradeQueryResponse, error) {
	r, err := service.NewTransService(s.d).TradeQueryByOutTradeNo(ctx, req.BrandId, req.OutTradeNo)
	if err != nil {
		return nil, err
	}
	resp := wxpay.TradeQueryResponse{
		BrandId:        r.BrandID,
		OutTradeNo:     r.OutTradeNo,
		WxTransId:      r.WxTransID,
		Attach:         r.Description,
		TradeType:      r.TradeType,
		TradeState:     r.TradeState,
		TradeStateDesc: r.TradeStateDesc,
		Amount: &wxpay.AmountInfo{
			Total:    int64(r.AmountInfo.Total),
			Currency: r.AmountInfo.Currency,
		},
		Payer: &wxpay.Payer{
			OpenId:    r.PayerInfo.SpOpenID,
			SubOpenId: r.PayerInfo.SubOpenID,
		},
		SettleInfo: &wxpay.SettleInfo{
			ProfitSharing: r.SettleInfo.ProfitSharing,
			SubsidyAmount: int64(r.SettleInfo.SubsidyAmount),
		},
		TimeExpire:  util.TimePtrToString(&r.ExpireTime, util.LayoutSecondWithTimeZoneAndT),
		TimeSuccess: util.TimePtrToString(r.SuccessTime, util.LayoutSecondWithTimeZoneAndT),
		ServiceRate: r.GetServiceRate(),
		ServiceFee:  r.GetServiceFee(),
	}
	return &resp, nil
}

// 关闭订单 POST: /api/v1/wxpay/trades/{out_trade_no}/close
func (s *Server) TradeClose(ctx context.Context, req *wxpay.TradeCloseRequest) (*wxpay.OperationResult, error) {
	if err := service.NewTransService(s.d).TradeClose(ctx, req.BrandId, req.OutTradeNo); err != nil {
		return nil, err
	}
	return &wxpay.OperationResult{Message: "SUCCESS"}, nil
}
